package cn.lbd.api.lambda;

import org.junit.jupiter.api.Test;

import java.net.Proxy;
import java.sql.Connection;
import java.util.*;
import java.util.function.*;

public class LambdaPractice {
    private List<Employee> lists = Arrays.asList(
            new Employee(12, "张三", 9999.99),
            new Employee(32, "李四", 8888.88),
            new Employee(52, "王五", 6999.99),
            new Employee(42, "胡时飞", 6000.11),
            new Employee(22, "贾科斯", 4999.11),
            new Employee(62, "傻子", 3444.44)
    );

    /**
     * 调用Coltections.sort() 方法，通过定制排序比较两个Employee (先按年龄比，年龄相同1.调用Coltections.sort() 方法，通过定制排序比较两个Employee (先按年龄比，年龄相同
     * 按姓名比)，使用Lambda作为参数传递
     */
    @Test
    public void test1() {
        //o1，o2：上下文推断  先比较年龄，年龄相同按姓名比
        Collections.sort(lists, (o1, o2) -> {
            if (o1.getAge() == o2.getAge()) {
                return o1.getName().compareTo(o2.getName());
            } else {
                return Integer.compare(o1.getAge(), o2.getAge());
            }
        });
        lists.forEach(System.out::println);
    }

    /**
     * ①声明函数式接口，接口中声明抽象方法，public String getValue(String str);
     * ②声明类TestLambda ，类中编写方法使用接口作为参数，将一个字符串转换成大写，
     * 并作为方法的返回值
     * ③再将一个字符串的第2个和第4个索引位置进行截取子串。
     */
    @Test
    public void test2() {
        String str = "abcdefg";
        System.out.println(transition(str, (e) -> {
            return e.toUpperCase();
        }));

        System.out.println(transition1(str, (e) -> {
            return e.substring(0, 4);
        }));

        BiFunction<Integer, Integer, String> bf = str::substring;
        String apply = bf.apply(0, 4);
        System.out.println(apply);
    }

    public String transition(String str, MyInterface<String> mi) {
        return mi.getValue(str);
    }

    public String transition1(String str, Function<String, String> fc) {
        return fc.apply(str);
    }

    /**
     * ①声明一个带两个泛型的函数式接口，泛型类型为<T,R> T 为参数，R为返回值
     * ②接口中声明对应抽象方法。
     * ③在TestLambda类中声明方法，使用接口作为参数，计算两个long型参数的和。。
     * ④再计算两个long 型参数的乘积
     */
    @Test
    public void test3() {
        System.out.println(operator(100l, 200l, (n1, n2) -> n1 + n2));
        System.out.println(operator1(100l, 200l, (n1, n2) -> n1 * n2));

        BiFunction<Long, Long, Long> biFunction = (x, y) -> x - y;
        Long apply = biFunction.apply(300l, 200l);
        System.out.println(apply);
    }

    public Long operator(Long num1, Long num2, MyFunction<Long, Long> mf) {
        return mf.execute(num1, num2);
    }

    public Long operator1(Long num1, Long num2, BiFunction<Long, Long, Long> mf) {
        return mf.apply(num1, num2);
    }

    @Test
    public void test4() {
        happy(100.11, (money) -> System.out.println("消费了" + money + "元"));
    }

    /**
     * @param money
     * @param cs    消费型接口，只有输入
     */
    public void happy(Double money, Consumer<Double> cs) {
        cs.accept(money);
    }

    @Test
    public void test5() {
        generator(10, () -> {
            return (int) (Math.random() * 100);
        }).forEach(System.out::println);

    }

    /**
     * @param num      生成数字个数
     * @param supplier 供给型接口，只有输出
     * @return
     */
    public List<Integer> generator(int num, Supplier<Integer> supplier) {
        List<Integer> numLists = new ArrayList<>();
        for (int i = 0; i < num; i++) {
            Integer n = supplier.get();
            numLists.add(n);
        }
        return numLists;
    }


    @Test
    public void test6() {
        String str = "aaaaa中国共产党万岁aaaaa";
        System.out.println(transfer(str, (s) -> s.substring(5, 12)));

        BiFunction<Integer, Integer, String> biFunction = str::substring;

        String apply = biFunction.apply(5, 12);
        System.out.println(apply);
    }

    /**
     * @param str      要转换的字符串
     * @param function 函数式接口，输入输出都有
     * @return
     */
    public String transfer(String str, Function<String, String> function) {
        return function.apply(str);
    }

    @Test
    public void test7() {
        //lambda
        /*predicate(70, age -> age >= 60);*/


        //方法引用 + 函数式接口
        LambdaPractice practice = new LambdaPractice();
        //若Lambda 参数列表中的第一参数式实例方法的调用者，而第二个参数式实例方法参数时，可以用类名::方法名
        Predicate<Integer> predicate = LambdaPractice::compare;
        int age = 58;
        if (predicate.test(age)) {
            System.out.println("年龄" + age + "岁=>退休");
        } else {
            System.out.println("年龄" + age + "岁=>不退休");
        }
    }

    public static boolean compare(Integer age) {
        if (age >= 60) {
            return true;
        } else {
            return false;
        }
    }

    //若Lambda 参数列表中的第一参数式实例方法的调用者，而第二个参数式实例方法参数时，可以用类名::方法名
    @Test
    public void test03(){
        BiPredicate<String, String> bp1 = (x, y) -> x.equals(y);
        System.out.println(bp1.test("a","b"));

        BiPredicate<String, String> bp2 = String::equals;
        System.out.println(bp2.test("c","c"));
    }

    /**
     * @param age       带判断的年龄
     * @param predicate 断定型接口
     */
    public void predicate(Integer age, Predicate<Integer> predicate) {
        if (predicate.test(age)) {
            System.out.println("年龄" + age + "岁=>退休");
        } else {
            System.out.println("年龄" + age + "岁=>不退休");
        }
    }

    @Test
    public void test8() {
        /*Consumer<String> com1 = (x) -> System.out.println(x);*/
        Consumer<String> com = System.out::println;
        com.accept("abc");
    }

    @Test
    public void test9(){
        Supplier<Person> supplier = () -> new Person();
        Person person = supplier.get();
        System.out.println(person);

        Supplier<Person> supplier1 = Person::new;
        System.out.println(supplier1.get());

        Function<String,Person> function = (x) -> new Person(x);
        Person person1 = function.apply("张三");
        System.out.println(person1);

        Function<String,Person> function2 = Person::new;
        System.out.println(function2.apply("李四"));

        BiFunction<String,Integer,Person> function1 = (x,y) -> new Person(x,y);
        Person person2 = function1.apply("张三",11);
        System.out.println(person2);

        BiFunction<String,Integer,Person> function3 = Person::new;
        System.out.println(function1.apply("李四", 12));

    }


    @Test
    public void test10(){
        Function<Integer,String[]> supplier = (x) -> new String[x];

        Function<Integer,String[]> function = String[]::new;
        String[] strings = function.apply(10);
        System.out.println(strings.length);
    }



    /*@Test
    public void test9(){
        HashSet set = new HashSet();
        Person p = new Person("aa",1001);
        Person p1 = new Person("bb",1002);
        set.add(p);
        set.add(p1);
        p1.name = "cc";
        set.remove(p1);
        System.out.println(set);  //aa cc
        set.add(new Person("cc",1001));
        System.out.println(set);
        set.add(new Person("aa",1001));
        System.out.println(set);

        int[] c = new int[1];
        System.out.println(c);
    }*/

}

class Person {
    String name;
    Integer id;

    public Person(){

    }

    public Person(String name){
        this.name = name;
    }

    public Person(String name, Integer id) {
        this.name = name;
        this.id = id;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", id=" + id +
                '}';
    }


    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Person person = (Person) o;

        if (name != null ? !name.equals(person.name) : person.name != null) return false;
        return id != null ? id.equals(person.id) : person.id == null;
    }

    @Override
    public int hashCode() {
        int result = name != null ? name.hashCode() : 0;
        result = 31 * result + (id != null ? id.hashCode() : 0);
        return result;
    }

}
